package org.ouwh.fw.schedule;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ScheduleThread implements Runnable {

	private static Log log = LogFactory.getLog(ScheduleThread.class);

	private volatile IScheduleTask task;

	private String name;

	private boolean running;

	private Thread thread;

	private volatile boolean isThreadDead;

	private String schedule;

	private ArrayList<TimePair> scheduleTime;

	private Thread taskThread;

	private volatile boolean isTaskThreadDead = true;

	public void setName(String name) {
		this.name = name;
	}

	public void startup() throws Exception {
		if (task == null) {
			throw new Exception("Schedule[" + name + "] no task.");
		}
		running = true;
		thread = new Thread(this);
		thread.setDaemon(false);
		thread.setName(this.name);
		thread.start();
	}

	public void run() {
		isThreadDead = false;
		log.info("Schedule[" + name + "]active");
		while (running) {
			try {
				Thread.sleep(5000);
				if (running) {
					if (isNowInSchedule()) {
						if (taskThread == null) {
							onScheduleBegin();
						}
					} else {
						if (taskThread != null) {
							onScheduleEnd();
						}
					}
				}
			} catch (InterruptedException ie) {
				// do nothing
			} catch (Exception e) {
				log.error("Schedule[" + name + "]execute error", e);
			}
		}
		log.info("Schedule[" + name + "]cancelled");
		isThreadDead = true;
	}

	public void shutdown() {
		this.running = false;
		try {
			task.end();
		} catch (Exception e) {
			log.error("Schedule[" + name + "]error in cancelling", e);
		}
		if (thread != null) {
			thread.interrupt();
		}
		if (taskThread != null) {
			try {
				taskThread.interrupt();
			} catch (Exception e) {
			}
		}
		while (!isThreadDead) {
			try {
				Thread.sleep(100);
			} catch (Exception e) {
			}
		}
		while (!isTaskThreadDead) {
			try {
				Thread.sleep(100);
			} catch (Exception e) {
			}
		}
	}

	public void setTask(IScheduleTask task) {
		this.task = task;
	}

	public void setSchedule(String schedule) {
		try {
			ArrayList<TimePair> tmpScheduleTime = new ArrayList<TimePair>();
			String[] freeTimeArray = schedule.split(";");
			for (int i = 0; i < freeTimeArray.length; i++) {
				String[] freeTimeStr = freeTimeArray[i].split("-");
				checkTime(freeTimeStr[0]);
				checkTime(freeTimeStr[1]);
				TimePair pair = new TimePair(freeTimeStr[0], freeTimeStr[1]);
				tmpScheduleTime.add(pair);
			}
			this.schedule = schedule;
			this.scheduleTime = tmpScheduleTime;
		} catch (Exception e) {
			log.error("", e);
		}
	}

	public String getSchedule() {
		return schedule;
	}

	public String getTaskInfo() {
		return task.getInfo();
	}

	public String getName() {
		return name;
	}

	private class TimePair {
		private String beginTime;

		private String endTime;

		TimePair(String beginTime, String endTime) {
			this.beginTime = beginTime;
			this.endTime = endTime;
		}

		public String getBeginTime() {
			return beginTime;
		}

		public String getEndTime() {
			return endTime;
		}
	}

	private void checkTime(String time) throws Exception {
		SimpleDateFormat format = new SimpleDateFormat("HH:mm");
		Date t = format.parse(time);
		String time2 = format.format(t);
		if (!time2.equals(time)) {
			throw new Exception("schedule incorrect, must be: HH:mm-HH:mm;...;HH:mm-HH:mm format" + time);
		}
	}

	private boolean isNowInSchedule() {
		Date t = new Date(System.currentTimeMillis());
		SimpleDateFormat format = new SimpleDateFormat("HH:mm");
		String now = format.format(t);
		ArrayList<TimePair> tmpScheduleTime = scheduleTime;
		for (int i = 0; i < tmpScheduleTime.size(); i++) {
			TimePair pair = tmpScheduleTime.get(i);
			if ((now.compareTo(pair.getBeginTime()) >= 0) && (now.compareTo(pair.getEndTime()) <= 0)) {
				return true;
			}
		}
		return false;
	}

	private void onScheduleBegin() {
		taskThread = new Thread() {
			public void run() {
				isTaskThreadDead = false;
				try {
					task.begin();
				} catch (Exception e) {
				}
				isTaskThreadDead = true;
			}
		};
		taskThread.setDaemon(false);
		taskThread.setName(name + "-TaskThread");
		taskThread.start();
	}

	private void onScheduleEnd() {
		try {
			task.end();
		} catch (Exception e) {
		}
		try {
			taskThread.interrupt();
		} catch (Exception e) {
		}
		taskThread = null;
	}

}
